#ifndef ___fat32_transaccionA1_crear_archivo

#define ___fat32_transaccionA1_crear_archivo 1

#include "f32_mto.c"

#include "f32_st01.c"
#include "f32_st02.c"
#include "f32_st03.c"
#include "f32_st10.c"
#include "f32_st11.c"
#include "f32_st13.c"
#include "f32_st14.c"

enum fat32trA1_errores {
  FAT32_A1_ARCHIVO_EXISTE = 1,
  FAT32_A1_RUTA_NO_EXISTE = 2,
  FAT32_A1_DISCO_LLENO = 3
};

struct fat32trA1_datos_entrada {
  char * rutaNuevoArchivo;
  unsigned int remitente;
  unsigned short permisos;
};

struct fat32trA1_datos_internos {
  char * rutaNuevoArchivo;
  char ** rutaConvertida;
  char ** rutaDirPadre;
  char * nombreArchivo;
  unsigned long long descriptorPadre;
  unsigned int remitenteMensaje;
  void * datosInternos;
  unsigned int conexion;
  unsigned char soloLectura;
  struct fat32_ref_entrada_directorio entrada;
  signed short errorDevuelto;
  fat32_lista_bloques_para_escribir * lbpe1;
};

void fat32tr_crear_archivo(const char *, unsigned int);
int fat32ctr_crear_archivo(FAT32_PARAMS_CREACION_TRANSACCION);
int fat32etr_crear_archivo(FAT32_PARAMS_TRANSACCION);

void fat32tr_crear_archivo (const char * ruta, unsigned int remitente, unsigned short permisosArchivo) {
  if (!(ruta && remitente)) return;
  struct fat32trA1_datos_entrada nuevosDatos;
  nuevosDatos.remitente = remitente;
  nuevosDatos.rutaNuevoArchivo = malloc(strlen(ruta) + 1);
  memcpy(nuevosDatos.rutaNuevoArchivo, ruta, strlen(ruta) + 1);
  nuevosDatos.permisos = permisosArchivo;
  fat32_crear_transaccion(&fat32ctr_crear_archivo, &nuevosDatos, sizeof nuevosDatos);
}

int fat32ctr_crear_archivo (FAT32_PARAMS_CREACION_TRANSACCION) {
  struct fat32trA1_datos_entrada * de = datosEntrada;
  struct fat32trA1_datos_internos * di = malloc(sizeof(struct fat32trA1_datos_internos));
  di -> rutaNuevoArchivo = de -> rutaNuevoArchivo;
  di -> remitenteMensaje = de -> remitente;
  di -> soloLectura = (((de -> permisos) & 2) || ((de -> permisos) & 16) || ((de -> permisos) & 128)) ? 1 : 0;
  *datos = di;
  *handler = &fat32etr_crear_archivo;
  return 0xE100;
}

int fat32etr_crear_archivo (FAT32_PARAMS_TRANSACCION) {
  unsigned char estado1;
  int estado2;
  estado2 = estado >> 8;
  estado1 = estado & 255;
  struct fat32trA1_datos_internos * datosT = *datos;
  switch (estado2) {
  case 0x01:
    estado1 = fat32_obtener_conexion(estado1, numeroTransaccion, &(datosT -> conexion), resultadoOperacion, datosOperacion);
    if (!estado1) {
      estado2 = 0xE1;
      estado1 = 1;
    }
    break;
  case 0x02:
    estado1 = fat32st_ubicar_entrada_directorio(estado1, numeroTransaccion, datosT -> rutaConvertida, &(datosT -> datosInternos),
                                                                                              resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> entrada = *((struct fat32_ref_entrada_directorio *) (datosT -> datosInternos));
      free(datosT -> datosInternos);
      estado2 = 0xE1;
      estado1 = 2;
    }
    break;
  case 0x03:
    estado1 = fat32st_bloquear_directorio_por_escritura_entrada(estado1, numeroTransaccion, datosT -> descriptorPadre, resultadoOperacion);
    if (!estado1) estado2 = 0x04;
    break;
  case 0x04:
    estado1 = fat32st_ubicar_entrada_directorio(estado1, numeroTransaccion, datosT -> rutaDirPadre, &(datosT -> datosInternos),
                                                                                            resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> entrada = *((struct fat32_ref_entrada_directorio *) (datosT -> datosInternos));
      free(datosT -> datosInternos);
      estado2 = 0x05;
    }
    break;
  case 0x05:
    estado1 = fat32st_crear_entrada_para_archivo(estado1, numeroTransaccion, datosT -> nombreArchivo, datosT -> soloLectura,
                                                 (datosT -> entrada).clusterInicial, &(datosT -> datosInternos), resultadoOperacion,
                                                 datosOperacion);
    if (!estado1) {
      datosT -> lbpe1 = ((struct fat32st14_resultado *) (datosT -> datosInternos)) -> lbpe;
      free(datosT -> datosInternos);
      estado2 = 0xE1;
      estado1 = 4;
    }
    break;
  case 0x06:
    estado1 = fat32st_ejecutar_lista_bloques_para_escribir(estado1, numeroTransaccion, datosT -> lbpe1, &(datosT -> datosInternos),
                                                                                                resultadoOperacion, datosOperacion);
    if (!estado1) {
      free(datosT -> lbpe1);
      estado2 = 0x07;
    }
    break;
  case 0x07:
    estado1 = fat32st_liberar_bloqueo(estado1, numeroTransaccion, datosT -> descriptorPadre);
    if (!estado1) {
      estado2 = 0xE1;
      estado1 = 5;
    }
    break;
  case 0x08:
    estado1 = fat32st_liberar_conexion(estado1, numeroTransaccion);
    if (!estado1) {
      estado2 = 0xE1;
      estado1 = 6;
    }
    break;
  case 0xE1:
    switch (estado1) {
    case 0:
      datosT -> errorDevuelto = -1;
      estado2 = 0x01;
      estado1 = 0;
      break;
    case 1:
      datosT -> rutaConvertida = fat32_obtener_ruta(datosT -> rutaNuevoArchivo);
      estado2 = 0x02;
      estado1 = 0;
      break;
    case 2:
      if (!(datosT -> entrada).resultado) datosT -> errorDevuelto = FAT32_A1_ARCHIVO_EXISTE;
      if (((datosT -> entrada).resultado) == 2) datosT -> errorDevuelto = FAT32_A1_RUTA_NO_EXISTE;
      if (((datosT -> entrada).resultado) == 1) 
        estado1 = 3;
      else
        estado1 = 5;
      break;
    case 3:
      datosT -> rutaDirPadre = fat32_copiar_ruta(datosT -> rutaConvertida);
      unsigned int posRuta;
      for (posRuta = 0; (datosT -> rutaDirPadre)[posRuta]; posRuta ++);
      datosT -> nombreArchivo = (datosT -> rutaDirPadre)[posRuta - 1];
      (datosT -> rutaDirPadre)[posRuta - 1] = NULL;
      estado2 = 0x03;
      estado1 = 0;
      datosT -> descriptorPadre = fat32_generar_descriptor(datosT -> rutaDirPadre, 1);
      break;
    case 4:
      if (!(datosT -> lbpe1)) {
        datosT -> errorDevuelto = FAT32_A1_DISCO_LLENO;
        estado1 = 5;
      } else {
        estado2 = 0x06;
        estado1 = 0;
      }
      break;
    case 5:
      if ((datosT -> errorDevuelto) == -1)
        mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_ARCHIVO_CREADO, (char *) (datosT -> rutaNuevoArchivo));
      else
        mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_NO_CREO_ARCHIVO, (char *) (datosT -> rutaNuevoArchivo),
                                                                                                         (int) (datosT -> errorDevuelto));
      estado2 = 0x08;
      estado1 = 0;
      break;
    case 6:
      fat32_destruir_ruta(datosT -> rutaConvertida);
      fat32_destruir_ruta(datosT -> rutaDirPadre);
      free(datosT -> nombreArchivo);
      free(datosT -> lbpe1);
      free(datosT -> rutaNuevoArchivo);
      fat32_liberar_descriptor(datosT -> descriptorPadre);
      free(datosT);
      *datos = NULL;
      estado1 = 0;
      estado2 = 0;
    }
    break;
  }
  return (estado2 << 8) | estado1;
}

#endif